/**
 * Project Name:fire-industry-DM-center
 * File Name:IProjectServiceImpl.java
 * Package Name:com.firestone.service.company.impl
 * Date:2018年4月12日上午9:34:33
 *
*/

package com.firestone.service.company.impl;

import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ScrolledPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilterBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.firestone.bean.dto.PageDTO;
import com.firestone.bean.dto.company.SearchDTO;
import com.firestone.bean.entity.elasticsearch.dm.DmMapProject;
import com.firestone.bean.entity.elasticsearch.im.DmImProject;
import com.firestone.core.constants.ConstantDmMapProjectKey;
import com.firestone.core.constants.ConstantKey;
import com.firestone.core.utils.TransUtil;
import com.firestone.dao.repository.DmImProjectRepository;
import com.firestone.service.company.IProjectService;

/**
 * @Description: TODO(产业地图企业管理)
 * @author CAIYJ
 * @date 2018年4月12日 上午9:34:33
 */
@Service
public class ProjectServiceImpl implements IProjectService {

    @Autowired
    private DmImProjectRepository imProjectRepository;

    @Autowired
    private ElasticsearchOperations elasticsearchOperations;

    @Override
    public Page<DmMapProject> mapList(SearchDTO search, PageDTO page)
            throws Exception {
        if (page == null) {
            page = new PageDTO();
        }
        StringQuery stringQuery = new StringQuery(getStringQuery(search),
                PageRequest.of(page.getPage(), page.getSize()),
                new Sort(Direction.DESC, ConstantDmMapProjectKey.chengliriqi));
        FetchSourceFilterBuilder builder = new FetchSourceFilterBuilder();
        builder.withIncludes(ConstantDmMapProjectKey.ID,
                ConstantDmMapProjectKey.name,
                ConstantDmMapProjectKey.main_business,
                ConstantDmMapProjectKey.address,
                ConstantDmMapProjectKey.address_area,
                ConstantDmMapProjectKey.address_country,
                ConstantDmMapProjectKey.address_province,
                ConstantDmMapProjectKey.dengjijiguan,
                ConstantDmMapProjectKey.chengliriqi,
                ConstantDmMapProjectKey.ismedical,
                ConstantDmMapProjectKey.isnative,
                ConstantDmMapProjectKey.fadingdaibiao);
        stringQuery.addSourceFilter(builder.build());
        Page<DmMapProject> pageVO = elasticsearchOperations
                .queryForPage(stringQuery, DmMapProject.class);
        return pageVO;
    }

    /**
     * @Description: TODO(生成企业搜索的条件)
     * @param search
     * @return
     * @throws Exception
     * @author CAIYJ
     * @date 2018年4月12日 下午4:46:23
     * @lastModifier CAIYJ
     */
    private String getStringQuery(SearchDTO search) throws Exception {
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        if (search != null) {
            if (StringUtils.isNotBlank(search.getAddress())) {
                bool.must(queryStringQuery(
                        TransUtil.queryStringTrans(search.getAddress()))
                                .field(ConstantDmMapProjectKey.address)
                                .analyzeWildcard(true));
            }
            if (StringUtils.isNotBlank(search.getAddressArea())) {
                bool.must(queryStringQuery(
                        TransUtil.queryStringTrans(search.getAddressArea()))
                                .field(ConstantDmMapProjectKey.address_area)
                                .analyzeWildcard(true));
            }
            if (StringUtils.isNotBlank(search.getAddressCity())) {
                bool.must(queryStringQuery(
                        TransUtil.queryStringTrans(search.getAddressCity()))
                                .field(ConstantDmMapProjectKey.address_city)
                                .analyzeWildcard(true));
            }
            if (StringUtils.isNotBlank(search.getAddressCountry())) {
                bool.must(queryStringQuery(
                        TransUtil.queryStringTrans(search.getAddressCity()))
                                .field(ConstantDmMapProjectKey.address_city)
                                .analyzeWildcard(true));
            }
            if (StringUtils.isNotBlank(search.getAddressProvince())) {
                bool.must(queryStringQuery(
                        TransUtil.queryStringTrans(search.getAddressProvince()))
                                .field(ConstantDmMapProjectKey.address_province)
                                .analyzeWildcard(true));
            }
            if (StringUtils.isNotBlank(search.getChengliriqiStart())) {
                bool.must(rangeQuery(ConstantDmMapProjectKey.chengliriqi)
                        .gte(search.getChengliriqiStart()));
            }
            if (StringUtils.isNotBlank(search.getChengliriqiEnd())) {
                bool.must(rangeQuery(ConstantDmMapProjectKey.chengliriqi)
                        .lte(search.getChengliriqiEnd()));
            }
            if (StringUtils.isNotBlank(search.getCname())) {
                bool.must(QueryBuilders.matchQuery(
                        ConstantDmMapProjectKey.cname, search.getCname()));
            }
            if (null != search.getCompanyPortraits()
                    && search.getCompanyPortraits().length > 0) {
                BoolQueryBuilder portraits = new BoolQueryBuilder();
                for (String str : search.getCompanyPortraits()) {
                    portraits.should(QueryBuilders.matchQuery(
                            ConstantDmMapProjectKey.company_portraits, str));
                }
                bool.must(portraits);
            }
            if (StringUtils.isNotBlank(search.getDengjijiguan())) {
                bool.must(QueryBuilders.matchQuery(
                        ConstantDmMapProjectKey.dengjijiguan,
                        search.getDengjijiguan()));
            }
            if (StringUtils.isNotBlank(search.getDescriber())) {
                bool.must(QueryBuilders.matchQuery(
                        ConstantDmMapProjectKey.describer,
                        search.getDescriber()));
            }
            if (StringUtils.isNotBlank(search.getFadingdaibiao())) {
                bool.must(queryStringQuery(
                        TransUtil.queryStringTrans(search.getFadingdaibiao()))
                                .field(ConstantDmMapProjectKey.fadingdaibiao)
                                .analyzeWildcard(true));
            }
            if (StringUtils.isNotBlank(search.getFazhaoriqiStart())) {
                bool.must(rangeQuery(ConstantDmMapProjectKey.fazhaoriqi)
                        .gte(search.getFazhaoriqiStart()));
            }
            if (StringUtils.isNotBlank(search.getFazhaoriqiEnd())) {
                bool.must(rangeQuery(ConstantDmMapProjectKey.fazhaoriqi)
                        .lte(search.getFazhaoriqiEnd()));
            }
            if (null != search.getIsmedical()
                    && search.getIsmedical().length > 0) {
                bool.must(QueryBuilders.termsQuery(
                        ConstantDmMapProjectKey.ismedical,
                        search.getIsmedical()));
            }
            if (StringUtils.isNotBlank(search.getIsnative())) {
                bool.must(QueryBuilders.termQuery(
                        ConstantDmMapProjectKey.isnative,
                        search.getIsnative()));
            }
            if (StringUtils.isNotBlank(search.getJingyingfanwei())) {
                bool.must(QueryBuilders.matchQuery(
                        ConstantDmMapProjectKey.jingyingfanwei,
                        search.getJingyingfanwei()));
            }
            if (StringUtils.isNotBlank(search.getJingyingzhuangtai())) {
                bool.must(QueryBuilders.matchQuery(
                        ConstantDmMapProjectKey.jingyingzhuangtai,
                        search.getJingyingzhuangtai()));
            }
            if (StringUtils.isNotBlank(search.getMainBusiness())) {
                bool.must(QueryBuilders.matchQuery(
                        ConstantDmMapProjectKey.main_business,
                        search.getMainBusiness()));
            }
            if (StringUtils.isNotBlank(search.getName())) {
                bool.must(queryStringQuery(
                        TransUtil.queryStringTrans(search.getName()))
                                .field(ConstantDmMapProjectKey.name)
                                .analyzeWildcard(true));
            }
            if (StringUtils.isNotBlank(search.getType())) {
                bool.must(QueryBuilders.termQuery(ConstantDmMapProjectKey.type,
                        search.getType()));
            }
            if (null != search.getZizhi() && search.getZizhi().length > 0) {
                BoolQueryBuilder zizhi = new BoolQueryBuilder();
                for (String str : search.getZizhi()) {
                    zizhi.should(QueryBuilders
                            .matchQuery(ConstantDmMapProjectKey.zizhi, str));
                }
                bool.must(zizhi);
            }
        }
        return bool.toString();
    }

    @Override
    public Page<DmImProject> imListByIds(Page<DmMapProject> page)
            throws Exception {
        if (page != null && page.hasContent()) {
            Set<String> set = new HashSet<>();
            for (DmMapProject project : page.getContent()) {
                set.add(project.getId());
            }
            String[] ids = set.toArray(new String[set.size()]);
            SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(
                    QueryBuilders.idsQuery(ConstantKey.ES_TYPE).addIds(ids))
                    .build();
            FetchSourceFilterBuilder builder = new FetchSourceFilterBuilder();
            builder.withIncludes(ConstantDmMapProjectKey.name,
                    ConstantDmMapProjectKey.ID);
            searchQuery.addSourceFilter(builder.build());
            searchQuery.setPageable(Pageable.unpaged());
            Page<DmImProject> list = imProjectRepository.search(searchQuery);
            return list;
        }
        return null;
    }

    @Async
    @Override
    public void push(SearchQuery searchQuery, Long... mapIds) throws Exception {
        // 区域ID为空，直接返回true
        if (null == searchQuery) {
            return;
        }
        searchQuery
                .setPageable(PageRequest.of(ConstantKey.ES_DEFAULT_SCROLL_PAGE,
                        ConstantKey.ES_DEFAULT_SCROLL_SIZE));
        ScrolledPage<DmMapProject> scroll = (ScrolledPage<DmMapProject>) elasticsearchOperations
                .startScroll(ConstantKey.ES_DEFAULT_SCROLL_TIME_IN_MILLIS,
                        searchQuery, DmMapProject.class);
        Set<String> ids = null;
        while (scroll.hasContent()) {
            ids = new HashSet<>();
            for (DmMapProject dmMapProject : scroll.getContent()) {
                ids.add(dmMapProject.getId());
            }
            Iterable<DmImProject> iterable = imProjectRepository
                    .findAllById(ids);
            Iterable<DmImProject> insertProjects = savaAllBuilder(
                    scroll.getContent(), iterable, mapIds);
            imProjectRepository.saveAll(insertProjects);
            scroll = (ScrolledPage<DmMapProject>) elasticsearchOperations
                    .continueScroll(scroll.getScrollId(),
                            ConstantKey.ES_DEFAULT_SCROLL_TIME_IN_MILLIS,
                            DmMapProject.class);
        }
    }

    /**
     * @Description: TODO(生成更新/新增企业信息)
     * @param source
     * @param target
     * @param mapIds
     * @return
     * @throws Exception
     * @author CAIYJ
     * @date 2018年4月16日 下午2:21:42
     * @lastModifier CAIYJ
     */
    private Iterable<DmImProject> savaAllBuilder(Iterable<DmMapProject> source,
            Iterable<DmImProject> target, Long... mapIds) throws Exception {
        List<DmImProject> list = new ArrayList<>();
        if (source != null) {
            DmImProject project = null;
            for (DmMapProject dmMapProject : source) {
                project = new DmImProject();
                BeanUtils.copyProperties(dmMapProject, project);
                if (target != null) {
                    for (DmImProject dmImProject : target) {
                        if (dmMapProject.getId().equals(dmImProject.getId())) {
                            TransUtil.fieldTransExcludeRecord(dmImProject,
                                    project,DmImProject.class);
                            TransUtil.categoryTransUp(dmImProject, project,
                                    mapIds);
                            break;
                        }
                    }
                } else {
                    TransUtil.categoryTransUp(null, project, mapIds);
                }
                list.add(project);
            }
        }
        return list;
    }

    @Async
    @Override
    public void pull(SearchQuery searchQuery, Long... mapIds) throws Exception {
        // 搜索条件为空，直接返回true
        if (null == searchQuery) {
            return;
        }
        searchQuery
                .setPageable(PageRequest.of(ConstantKey.ES_DEFAULT_SCROLL_PAGE,
                        ConstantKey.ES_DEFAULT_SCROLL_SIZE));
        ScrolledPage<DmImProject> scroll = (ScrolledPage<DmImProject>) elasticsearchOperations
                .startScroll(ConstantKey.ES_DEFAULT_SCROLL_TIME_IN_MILLIS,
                        searchQuery, DmImProject.class);
        List<DmImProject> insertProjects = null;
        List<DmImProject> deleteProjects = null;
        while (scroll.hasContent()) {
            insertProjects = new ArrayList<>();
            deleteProjects = new ArrayList<>();
            for (DmImProject dmImProject : scroll.getContent()) {
                TransUtil.categoryTransDown(dmImProject, mapIds);
                insertProjects.add(dmImProject);
                if ((null == mapIds || mapIds.length == 0)
                        && (dmImProject.getCategory() == null
                                || dmImProject.getCategory().size() == 0)) { // 传入区域为空，且产业地图DM层企业category为空，则从DM中移除
                    deleteProjects.add(dmImProject);
                }
            }
            imProjectRepository.saveAll(insertProjects);
            if (deleteProjects != null && deleteProjects.size() > 0) {
                imProjectRepository.deleteAll(deleteProjects);
            }
            scroll = (ScrolledPage<DmImProject>) elasticsearchOperations
                    .continueScroll(scroll.getScrollId(),
                            ConstantKey.ES_DEFAULT_SCROLL_TIME_IN_MILLIS,
                            DmImProject.class);
        }
    }

}
